package com.evil.common.es.util;

import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.es.dto.Summary;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.ParsedSingleBucketAggregation;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedReverseNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
import org.springframework.data.elasticsearch.core.AggregationsContainer;
import org.springframework.data.elasticsearch.core.ElasticsearchAggregations;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * es工具
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public class ElasticsearchUtil {

    public static final String NESTED = "NESTED";
    public static final String CONTROL = "CONTROL";
    public static final String VALUE = "VALUE";
    public static final String REV = "REV";

    public static String nested(String title) {
        return ESFieldUtil.underJoin(title, NESTED);
    }

    public static String control(String title) {
        return ESFieldUtil.underJoin(title, CONTROL);
    }

    public static String value(String title) {
        return ESFieldUtil.underJoin(title, VALUE);
    }

    public static String rev(String title) {
        return ESFieldUtil.underJoin(title, REV);
    }

    /**
     * 解析汇总结果
     *
     * @param summary               summary
     * @param aggregationsContainer aggregationsContainer
     * @param <T>                   <T>
     * @return Map
     */
    public static <T> Map<Summary<T>, Aggregations> aggregationsData(Summary<T> summary, AggregationsContainer<?> aggregationsContainer) {
        Aggregations aggregations = ElasticsearchUtil.getAggregations(aggregationsContainer);
        return ElasticsearchUtil.aggregationsData(summary, aggregations);
    }

    /**
     * 解析汇总结果
     *
     * @param summary      summary
     * @param aggregations aggregations
     * @param <T>          <T>
     * @return Map
     */
    public static <T> Map<Summary<T>, Aggregations> aggregationsData(Summary<T> summary, Aggregations aggregations) {
        Map<Summary<T>, Aggregations> result = new LinkedHashMap<>();

        if (Objects.nonNull(aggregations)) {
            Map<String, Aggregation> aggregationMap = aggregations.asMap();
            // nested 层
            String nestedTitle = ElasticsearchUtil.nested(summary.getTitle());
            if (aggregationMap.containsKey(nestedTitle)) {
                ParsedSingleBucketAggregation nestedAgg = (ParsedSingleBucketAggregation) aggregationMap.get(nestedTitle);
                // control 层
                String controlTitle = ElasticsearchUtil.control(summary.getTitle());
                Map<String, Aggregation> nestedAggMap = nestedAgg.getAggregations().asMap();
                if (nestedAggMap.containsKey(controlTitle)) {
                    ParsedFilter controlAgg = (ParsedFilter) nestedAggMap.get(controlTitle);
                    // value 层
                    String valueTitle = ElasticsearchUtil.value(summary.getTitle());
                    Map<String, Aggregation> controlAggMap = controlAgg.getAggregations().asMap();
                    if (controlAggMap.containsKey(valueTitle)) {
                        Aggregation aggregation = controlAggMap.get(valueTitle);
                        if (aggregation instanceof NumericMetricsAggregation.SingleValue) {
                            NumericMetricsAggregation.SingleValue parsedSum = (NumericMetricsAggregation.SingleValue) aggregation;
                            result.put(summary.copy(parsedSum.getValueAsString()), null);
                        } else {
                            if (aggregation instanceof ParsedDateHistogram) {
                                // 时间聚合
                                ((ParsedDateHistogram) aggregation).getBuckets()
                                        .forEach(e -> ElasticsearchUtil.test(result, summary, e.getKeyAsString(), e.getAggregations()));
                            }
                            if (aggregation instanceof ParsedTerms) {
                                // 普通聚合
                                ((ParsedTerms) aggregation).getBuckets()
                                        .forEach(e -> ElasticsearchUtil.test(result, summary, e.getKeyAsString(), e.getAggregations()));
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 解析汇总结果
     *
     * @param aggregationsContainer aggregationsContainer
     * @param <T>                   <T>
     * @return Map
     */
    public static <T> Aggregations getAggregations(AggregationsContainer<?> aggregationsContainer) {
        if (Objects.nonNull(aggregationsContainer)) {
            if (!(aggregationsContainer instanceof ElasticsearchAggregations)) {
                throw new BusinessException(RCodeEnum.ERROR_RUNTIME);
            }
            return ((ElasticsearchAggregations) aggregationsContainer).aggregations();
        }
        throw new BusinessException(RCodeEnum.ERROR_RUNTIME);
    }

    private static <T, A extends Aggregation> void test(Map<Summary<T>, Aggregations> result, Summary<T> summary, String valueAggBucketKey, Aggregations aggs) {
        String revTitle = ElasticsearchUtil.rev(summary.getTitle());
        Map<String, Aggregation> valueAggMap = aggs.asMap();
        if (valueAggMap.containsKey(revTitle)) {
            ParsedReverseNested revAgg = (ParsedReverseNested) valueAggMap.get(revTitle);
            aggs = revAgg.getAggregations();
        }
        result.put(summary.copy(valueAggBucketKey), aggs);
    }
}
